package cn.com.idmy.cloud.service;

import cn.com.idmy.base.TreeNode;
import cn.com.idmy.base.util.Assert;
import cn.com.idmy.orm.core.Query;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

public interface DefaultTreeNodeService<T extends TreeNode<T>> extends DefaultService<T, Long> {
    void fixTree();

    boolean hasChildren(long id);

    @NotNull T getRoot(long id);

    @Nullable T getParent(long id);

    boolean isRoot(long id);

    boolean isLeaf(long id);

    @NotNull
    default T getTree(long treeId) {
        return listTrees(treeId, q().eq(TreeNode::getTreeId, treeId)).getFirst();
    }

    @NotNull
    List<T> listTrees(long treeId, @NotNull Query<T> q);

    @NotNull
    default List<T> listTreesByDepth(long treeId, int depth) {
        return listTreesByDepth(treeId, depth, q());
    }

    @NotNull
    default List<T> listTreesByDepth(long treeId, int depth, @NotNull Query<T> q) {
        Assert.isTrue(depth > 0, "深度必须大于0：{}", depth);
        return listTrees(treeId, q.ge(TreeNode::getLevel, depth));
    }

    @NotNull
    default List<T> listDescendants(long id) {
        return listDescendants(id, q());
    }

    @NotNull
    List<T> listDescendants(long id, @NotNull Query<T> q);

    @NotNull
    default List<T> listSelfAndDescendants(long id) {
        return listSelfAndDescendants(id, q());
    }

    @NotNull
    List<T> listSelfAndDescendants(long id, @NotNull Query<T> q);

    @NotNull
    default List<T> listByLevel(long treeId, int level) {
        return listByLevel(treeId, level, q());
    }

    @NotNull
    List<T> listByLevel(long treeId, int level, @NotNull Query<T> q);

    @NotNull
    List<T> listPathsById(long id);

    @NotNull
    List<T> listRoots(@NotNull Query<T> q);

    @NotNull
    default List<T> allRoots() {
        return listRoots(q());
    }

    @NotNull
    List<T> listChildren(long id, @NotNull Query<T> q);

    @NotNull
    default List<T> listChildren(long id) {
        return listChildren(id, q());
    }

    @NotNull
    List<T> listSelfAndChildren(long id, @NotNull Query<T> q);

    @NotNull
    default List<T> listSelfAndChildren(long id) {
        return listSelfAndChildren(id, q());
    }
}
